   This is an introduction to `Programming in Emacs Lisp', for people
who are not programmers.

   Edition 1.05, 21 October 1997

   Copyright (C) 1990, '91, '92, '93, '94, '95, '97 Free Software
Foundation, Inc.

   Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

   Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the sections entitled "Copying" and "GNU General Public License"
are included exactly as in the original, and provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.

   Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.

X Axis Tic Marks
----------------

   The first function should print the X axis tic marks.  We must
specify the tic marks themselves and their spacing:

     (defvar X-axis-label-spacing
       (if (boundp 'graph-blank)
           (* 5 (length graph-blank)) 5)
       "Number of units from one X axis label to next.")

(Note that the value of `graph-blank' is set by another `defvar'.  The
`boundp' predicate checks whether it has already been set; `boundp'
returns `nil' if it has not.  If `graph-blank' were unbound and we did
not use this conditional construction, we would receive an error
message saying `Symbol's value as variable is void'.)

     (defvar X-axis-tic-symbol "|"
       "String to insert to point to a column in X axis.")

   The goal is to make a line that looks like this:

            |   |    |    |

   The first tic is indented so that it is under the first column,
which is indented to provide space for the Y axis labels.

   A tic element consists of the blank spaces that stretch from one tic
to the next plus a tic symbol.  The number of blanks is determined by
the width of the tic symbol and the `X-axis-label-spacing'.

   The code looks like this:

     ;;; X-axis-tic-element
     ...
     (concat
      (make-string
       ;; Make a string of blanks.
       (-  (* symbol-width X-axis-label-spacing)
           (length X-axis-tic-symbol))
       ? )
      ;; Concatenate blanks with tic symbol.
      X-axis-tic-symbol)
     ...

   Next, we determine how many blanks are needed to indent the first tic
mark to the first column of the graph.  This uses the value of
`full-Y-label-width' passed it by the `print-graph' function.

   The code to make `X-axis-leading-spaces' looks like this:

     ;; X-axis-leading-spaces
     ...
     (make-string full-Y-label-width ? )
     ...

   We also need to determine the length of the horizontal axis, which is
the length of the numbers list, and the number of tics in the horizontal
axis:

     ;; X-length
     ...
     (length numbers-list)

     ;; tic-width
     ...
     (* symbol-width X-axis-label-spacing)

     ;; number-of-X-tics
     (if (zerop (% (X-length tic-width)))
         (/ (X-length tic-width))
       (1+ (/ (X-length tic-width))))

   All this leads us directly to the function for printing the X axis
tic line:

     (defun print-X-axis-tic-line
       (number-of-X-tics X-axis-leading-spaces X-axis-tic-element)
       "Print tics for X axis."
         (insert X-axis-leading-spaces)
         (insert X-axis-tic-symbol)  ; Under first column.
         ;; Insert second tic in the right spot.
         (insert (concat
                  (make-string
                   (-  (* symbol-width X-axis-label-spacing)
                       ;; Insert white space up to second tic symbol.
                       (* 2 (length X-axis-tic-symbol)))
                   ? )
                  X-axis-tic-symbol))
         ;; Insert remaining tics.
         (while (> number-of-X-tics 1)
           (insert X-axis-tic-element)
           (setq number-of-X-tics (1- number-of-X-tics))))

   The line of numbers is equally straightforward:

   First, we create a numbered element with blank spaces before each
number:

     (defun X-axis-element (number)
       "Construct a numbered X axis element."
       (let ((leading-spaces
              (-  (* symbol-width X-axis-label-spacing)
                  (length (int-to-string number)))))
         (concat (make-string leading-spaces ? )
                 (int-to-string number))))

   Next, we create the function to print the numbered line, starting
with the number "1" under the first column:

     (defun print-X-axis-numbered-line
       (number-of-X-tics X-axis-leading-spaces)
       "Print line of X-axis numbers"
       (let ((number X-axis-label-spacing))
         (insert X-axis-leading-spaces)
         (insert "1")
         (insert (concat
                  (make-string
                   ;; Insert white space up to next number.
                   (-  (* symbol-width X-axis-label-spacing) 2)
                   ? )
                  (int-to-string number)))
         ;; Insert remaining numbers.
         (setq number (+ number X-axis-label-spacing))
         (while (> number-of-X-tics 1)
           (insert (X-axis-element number))
           (setq number (+ number X-axis-label-spacing))
           (setq number-of-X-tics (1- number-of-X-tics)))))

   Finally, we need to write the `print-X-axis' that uses
`print-X-axis-tic-line' and `print-X-axis-numbered-line'.

   The function must determine the local values of the variables used
by both `print-X-axis-tic-line' and `print-X-axis-numbered-line', and
then it must call them.  Also, it must print the carriage return that
separates the two lines.

   The function consists of a varlist that specifies five local
variables, and calls to each of the two line printing functions:

     (defun print-X-axis (numbers-list)
       "Print X axis labels to length of NUMBERS-LIST."
       (let* ((leading-spaces
               (make-string full-Y-label-width ? ))
            ;; symbol-width is provided by graph-body-print
            (tic-width (* symbol-width X-axis-label-spacing))
            (X-length (length numbers-list))
            (X-tic
             (concat
              (make-string
               ;; Make a string of blanks.
               (-  (* symbol-width X-axis-label-spacing)
                   (length X-axis-tic-symbol))
               ? )
              ;; Concatenate blanks with tic symbol.
              X-axis-tic-symbol))
            (tic-number
             (if (zerop (% X-length tic-width))
                 (/ X-length tic-width)
               (1+ (/ X-length tic-width)))))
         (print-X-axis-tic-line tic-number leading-spaces X-tic)
         (insert "\n")
         (print-X-axis-numbered-line tic-number leading-spaces)))

   You can test `print-X-axis':

  1. Install `X-axis-tic-symbol', `X-axis-label-spacing',
     `print-X-axis-tic-line', as well as `X-axis-element',
     `print-X-axis-numbered-line', and `print-X-axis'.

  2. Copy the following expression:

          (progn
           (let ((full-Y-label-width 5)
                 (symbol-width 1))
             (print-X-axis
              '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))))

  3. Switch to the `*scratch*' buffer and place the cursor where you
     want the axis labels to start.

  4. Type `M-:' (`eval-expression').

  5. Yank the test expression into the minibuffer with `C-y' (`yank)'.

  6. Press <RET> to evaluate the expression.

   Emacs will print the horizontal axis like this:

          |   |    |    |    |
          1   5   10   15   20

Printing the Whole Graph
========================

   Now we are nearly ready to print the whole graph.

   The function to print the graph with the proper labels follows the
outline we created earlier (see A Graph with Labelled Axes),
but with additions.

   Here is the outline:

     (defun print-graph (numbers-list)
       "DOCUMENTATION..."
       (let ((height  ...
             ...))
         (print-Y-axis height ... )
         (graph-body-print numbers-list)
         (print-X-axis ... )))

   The final version is different from what we planned in two ways:
first, it contains additional values calculated once in the varlist;
second, it carries an option to specify the labels' increment per row.
This latter feature turns out to be essential; otherwise a graph may
have more rows than fit on a display or on a sheet of paper.

   This new feature requires a change to the `Y-axis-column' function,
to add `vertical-step' to it.  The function looks like this:

     ;;; Final version.
     (defun Y-axis-column
       (height width-of-label &optional vertical-step)
       "Construct list of labels for Y axis.
     HEIGHT is maximum height of graph.
     WIDTH-OF-LABEL is maximum width of label.
     VERTICAL-STEP, an option, is a positive integer
     that specifies how much a Y axis label increments
     for each line.  For example, a step of 5 means
     that each line is five units of the graph."
       (let (Y-axis
             (number-per-line (or vertical-step 1)))
         (while (> height 1)
           (if (zerop (% height Y-axis-label-spacing))
               ;; Insert label.
               (setq Y-axis
                     (cons
                      (Y-axis-element
                       (* height number-per-line)
                       width-of-label)
                      Y-axis))
             ;; Else, insert blanks.
             (setq Y-axis
                   (cons
                    (make-string width-of-label ? )
                    Y-axis)))
           (setq height (1- height)))
         ;; Insert base line.
         (setq Y-axis (cons (Y-axis-element
                             (or vertical-step 1)
                             width-of-label)
                            Y-axis))
         (nreverse Y-axis)))

   The values for the maximum height of graph and the width of a symbol
are computed by `print-graph' in its `let' expression; so
`graph-body-print' must be changed to accept them.

     ;;; Final version.
     (defun graph-body-print (numbers-list height symbol-width)
       "Print a bar graph of the NUMBERS-LIST.
     The numbers-list consists of the Y-axis values.
     HEIGHT is maximum height of graph.
     SYMBOL-WIDTH is number of each column."
       (let (from-position)
         (while numbers-list
           (setq from-position (point))
           (insert-rectangle
            (column-of-graph height (car numbers-list)))
           (goto-char from-position)
           (forward-char symbol-width)
           ;; Draw graph column by column.
           (sit-for 0)
           (setq numbers-list (cdr numbers-list)))
         ;; Place point for X axis labels.
         (forward-line height)
         (insert "\n")))

   Finally, the code for the `print-graph' function:

     ;;; Final version.
     (defun print-graph
       (numbers-list &optional vertical-step)
       "Print labelled bar graph of the NUMBERS-LIST.
     The numbers-list consists of the Y-axis values.

     Optionally, VERTICAL-STEP, a positive integer,
     specifies how much a Y axis label increments for
     each line.  For example, a step of 5 means that
     each row is five units."
       (let* ((symbol-width (length graph-blank))
              ;; `height' is both the largest number
              ;; and the number with the most digits.
              (height (apply 'max numbers-list))
              (height-of-top-line
               (if (zerop (% height Y-axis-label-spacing))
                   height
                 ;; else
                 (* (1+ (/ height Y-axis-label-spacing))
                    Y-axis-label-spacing)))
              (vertical-step (or vertical-step 1))
              (full-Y-label-width
               (length
                (concat
                 (int-to-string
                  (* height-of-top-line vertical-step))
                 Y-axis-tic))))

         (print-Y-axis
          height-of-top-line full-Y-label-width vertical-step)
         (graph-body-print
          numbers-list height-of-top-line symbol-width)
         (print-X-axis numbers-list)))

Testing `print-graph'
---------------------

   We can test the `print-graph' function with a short list of numbers

  1. Install the final versions of `Y-axis-column', `graph-body-print',
     and `print-graph' (in addition to the rest of the code.)

  2. Copy the following expression:

          (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1))

  3. Switch to the `*scratch*' buffer and place the cursor where you
     want the axis labels to start.

  4. Type `M-:' (`eval-expression').

  5. Yank the test expression into the minibuffer with `C-y' (`yank)'.

  6. Press <RET> to evaluate the expression.

   Emacs will print a graph that looks like this:

     10 -

              *
             **   *
      5 -   ****  *
            **** ***
          * *********
          ************
      1 - *************

          |   |    |    |
          1   5   10   15

   On the other hand, if you pass `print-graph' a `vertical-step' value
of 2, by evaluating this expression:

     (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2)

The graph looks like this:

     20 -

              *
             **   *
     10 -   ****  *
            **** ***
          * *********
          ************
      2 - *************

          |   |    |    |
          1   5   10   15

(A question: is the `2' on the bottom of the vertical axis a bug or a
feature?  If you think it is a bug, and should be a `1' instead, (or
even a `0'), you can modify the sources.)

Graphing Numbers of Words and Symbols
-------------------------------------

   Now for the graph for which all this code was written: a graph that
shows how many function definitions contain fewer than 10 words and
symbols, how many contain between 10 and 19 words and symbols, how many
contain between 20 and 29 words and symbols, and so on.

   This is a multi-step process.  First make sure you have loaded all
the requisit code.

   It is a good idea to reset the value of `top-of-ranges' in case you
have sent it to some different value.  You can evaluate the following:

     (setq top-of-ranges
      '(10  20  30  40  50
        60  70  80  90 100
       110 120 130 140 150
       160 170 180 190 200
       210 220 230 240 250
       260 270 280 290 300)

Next create a list of the number of words and symbols in each range.

Evaluate the following:

     (setq list-for-graph
            (defuns-per-range
              (sort
               (recursive-lengths-list-many-files
                (directory-files "/usr/local/emacs/lisp"
                                 t ".+el$"))
               '<)
              top-of-ranges))

On my machine, this takes about an hour.  It looks though 303 Lisp
files in my copy of Emacs version 19.23.  After all that computing, the
`list-for-graph' has this value:

     (537 1027 955 785 594 483 349 292 224 199 166 120 116 99
     90 80 67 48 52 45 41 33 28 26 25 20 12 28 11 13 220)

This means that my copy of Emacs has 537 function definitions with
fewer than 10 words or symbols in them, 1,027 function definitions with
10 to 19 words or symbols in them, 955 function definitions with 20 to
29 words or symbols in them, and so on.

   Clearly, just by looking at this list we can see that most function
definitions contain ten to thirty words and symbols.

   Now for printing.  We do *not* want to print a graph that is 1,030
lines high ...  Instead, we should print a graph that is fewer than
twenty-five lines high.  A graph that height can be displayed on almost
any monitor, and easily printed on a sheet of paper.

   This means that each value in `list-for-graph' must be reduced to
one-fiftieth it present value.

   Here is a short function to do just that, using two functions we have
not yet seen, `mapcar' and `lambda'.

     (defun one-fiftieth (full-range)
       "Return list, each number one-fiftieth of previous."
      (mapcar '(lambda (arg) (/ arg 50)) full-range))

A `lambda' Expression
.....................

   `lambda' is the symbol for an anonymous function, a function without
a name.  Every time you use an anonymous function, you need to include
its whole body.

Thus,

     (lambda (arg) (/ arg 50))

is a function definition that says `return the value resulting from
dividing whatever is passed to me as `arg' by 50'.

   Earlier, for example, we had a function `multiply-by-seven'; it
multiplied its argument by 7.  This function is similar, except it
divides its argument by 50; and, it has no name.  The anonymous
equivalent of `multiply-by-seven' is:

     (lambda (number) (* 7 number))

(see The `defun' Special Form.)

If we want to multiply 3 by 7, we can write:

     (multiply-by-seven 3)
      \_______________/ ^
              |         |
           function  argument

This expression returns 21.

Similarly, we can write:

     ((lambda (number) (* 7 number)) 3)
      \____________________________/ ^
                    |                |
           anonymous function     argument

If we want to divide 100 by 50, we can write:

     ((lambda (arg) (/ arg 50)) 100)
      \______________________/  \_/
                  |              |
         anonymous function   argument

This expression returns 2.  The 100 is passed to the function, which
divides that number by 50.

   See Lambda Expressions (elisp), for more about
`lambda'.  Lisp and lambda expressions derive from the Lambda Calculus.

The `mapcar' Function
.....................

   `mapcar' is a function that calls its first argument with each
element of its second argument, in turn.  The second argument must be a
sequence.

For example,

     (mapcar '1+ '(2 4 6))
          => (3 5 7)

The function `1+' which adds one to its argument, is executed on *each*
element of the list, and a new list is returned.

   Contrast this with `apply', which applies its first argument to all
the remaining.  (see Readying a Graph, for a
explanation of `apply'.)

   In the definition of `one-fiftieth', the first argument is the
anonymous function:

     (lambda (arg) (/ arg 50))

and the second argument is `full-range', which will be bound to
`list-for-graph'.

   The whole expression looks like this:

     (mapcar '(lambda (arg) (/ arg 50)) full-range))

   See Mapping Functions (elisp), for more about
`mapcar'.

   Using the `one-fiftieth' function, we can generate a list in which
each element is one-fiftieth the size of the corresponding element in
`list-for-graph'.

     (setq fiftieth-list-for-graph
           (one-fiftieth list-for-graph))

   The resulting list looks like this:

     (10 20 19 15 11 9 6 5 4 3 3 2 2
     1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 4)

This we are almost ready to print!  (We also notice the loss of
information: many of the higher ranges are 0, meaning that fewer than
50 defuns had that many words or symbols--but not necessarily meaning
that none had that many words or symbols.)

Another Bug ... Most Insidious
..............................

   I said `almost ready to print'!  Of course, there is a bug in the
`print-graph' function ...  It has a `vertical-step' option, but not a
`horizontal-step' option.  The `top-of-range' scale goes from 10 to 300
by tens.  But the `print-graph' function will print only by ones.

   This is a classic example of what some consider the most insidious
type of bug, the bug of omission.  This is not the kind of bug you can
find by studying the code, for it is not in the code; it is an omitted
feature.  Your best actions are to try your program early and often;
and try to arrange, as much as you can, to write code that is easy to
understand and easy to change.  Try to be aware, whenever you can, that
whatever you have written, *will* be rewritten, if not soon,
eventually.  A hard maxim to follow.

   It is the `print-X-axis-numbered-line' function that needs the work;
and then the `print-X-axis' and the `print-graph' functions need to be
adapted.  Not much needs to be done; there is one nicety: the numbers
ought to line up under the tic marks.  This takes a little thought.

   Here is the corrected `print-X-axis-numbered-line':

     (defun print-X-axis-numbered-line
       (number-of-X-tics X-axis-leading-spaces
        &optional horizontal-step)
       "Print line of X-axis numbers"
       (let ((number X-axis-label-spacing)
             (horizontal-step (or horizontal-step 1)))
         (insert X-axis-leading-spaces)
         ;; Delete extra leading spaces.
         (delete-char
          (- (1-
              (length (int-to-string horizontal-step)))))
         (insert (concat
                  (make-string
                   ;; Insert white space.
                   (-  (* symbol-width
                          X-axis-label-spacing)
                       (1-
                        (length
                         (int-to-string horizontal-step)))
                       2)
                   ? )
                  (int-to-string
                   (* number horizontal-step))))
         ;; Insert remaining numbers.
         (setq number (+ number X-axis-label-spacing))
         (while (> number-of-X-tics 1)
           (insert (X-axis-element
                    (* number horizontal-step)))
           (setq number (+ number X-axis-label-spacing))
           (setq number-of-X-tics (1- number-of-X-tics)))))

   If you are reading this in Info, you can see the new versions of
`print-X-axis' `print-graph' and evaluate them.  If you are reading
this in a printed book, you can see the changed lines here (the full
text is too much to print).

     (defun print-X-axis (numbers-list horizontal-step)
       "Print X axis labels to length of NUMBERS-LIST.
     Optionally, HORIZONTAL-STEP, a positive integer,
     specifies how much an X  axis label increments for
     each column."
     ;; Value of symbol-width and full-Y-label-width
     ;; are passed by `print-graph'.
       (let* ((leading-spaces
               (make-string full-Y-label-width ? ))
            ;; symbol-width is provided by graph-body-print
            (tic-width (* symbol-width X-axis-label-spacing))
            (X-length (length numbers-list))
            (X-tic
             (concat
              (make-string
               ;; Make a string of blanks.
               (-  (* symbol-width X-axis-label-spacing)
                   (length X-axis-tic-symbol))
               ? )
              ;; Concatenate blanks with tic symbol.
              X-axis-tic-symbol))
            (tic-number
             (if (zerop (% X-length tic-width))
                 (/ X-length tic-width)
               (1+ (/ X-length tic-width)))))

         (print-X-axis-tic-line
          tic-number leading-spaces X-tic)
         (insert "\n")
         (print-X-axis-numbered-line
          tic-number leading-spaces horizontal-step)))

     (defun print-graph
       (numbers-list &optional vertical-step horizontal-step)
       "Print labelled bar graph of the NUMBERS-LIST.
     The numbers-list consists of the Y-axis values.

     Optionally, VERTICAL-STEP, a positive integer,
     specifies how much a Y axis label increments for
     each line.  For example, a step of 5 means that
     each row is five units.

     Optionally, HORIZONTAL-STEP, a positive integer,
     specifies how much an X  axis label increments for
     each column."
       (let* ((symbol-width (length graph-blank))
              ;; `height' is both the largest number
              ;; and the number with the most digits.
              (height (apply 'max numbers-list))
              (height-of-top-line
               (if (zerop (% height Y-axis-label-spacing))
                   height
                 ;; else
                 (* (1+ (/ height Y-axis-label-spacing))
                    Y-axis-label-spacing)))
              (vertical-step (or vertical-step 1))
              (full-Y-label-width
               (length
                (concat
                 (int-to-string
                  (* height-of-top-line vertical-step))
                 Y-axis-tic))))
         (print-Y-axis
          height-of-top-line full-Y-label-width vertical-step)
         (graph-body-print
             numbers-list height-of-top-line symbol-width)
         (print-X-axis numbers-list horizontal-step)))

The Printed Graph
-----------------

   When made and installed, you can call the `print-graph' command like
this:

     (print-graph fiftieth-list-for-graph 50 10)

   Here is the graph:

     1000 -  *
             **
             **
             **
             **
      750 -  ***
             ***
             ***
             ***
             ****
      500 - *****
            ******
            ******
            ******
            *******
      250 - ********
            *********                     *
            ***********                   *
            *************                 *
       50 - ***************** *           *
            |   |    |    |    |    |    |    |
           10  50  100  150  200  250  300  350

   The largest group of functions contain 10 - 19 words and symbols
each.

Index
*****

   MENU ENTRY: NODE NAME.

About the Author
****************

     Robert J. Chassell has worked with GNU Emacs since 1985.  He writes
     and edits, teaches Emacs and Emacs Lisp, and is a director and the
     Secretary/Treasurer of the Free Software Foundation, Inc.  He has
     an abiding interest in social and economic history and flies his
     own airplane.